using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using HslCommunication.BasicFramework;

namespace HslCommunication.Core.Net
{
	/// <summary>
	/// 基于单次无协议的网络交互的基类，通常是串口协议扩展成网口协议的基类<br />
	/// Base class based on a single non-protocol network interaction, usually the base class that the serial port protocol is extended to the network port protocol
	/// </summary>
	public class NetworkDeviceSoloBase : NetworkDeviceBase
	{
		private int sleepTime = 20;

		/// <inheritdoc cref="P:HslCommunication.Serial.SerialBase.SleepTime" />
		public int SleepTime
		{
			get
			{
				return sleepTime;
			}
			set
			{
				if (value > 0)
				{
					sleepTime = value;
				}
			}
		}

		/// <summary>
		/// 实例化一个默认的对象<br />
		/// Instantiate a default object
		/// </summary>
		public NetworkDeviceSoloBase()
		{
			base.ReceiveTimeOut = 5000;
		}

		/// <summary>
		/// 从串口接收一串数据信息，可以指定是否一定要接收到数据<br />
		/// Receive a string of data information from the serial port, you can specify whether you must receive data
		/// </summary>
		/// <param name="socket">串口对象</param>
		/// <param name="awaitData">是否必须要等待数据返回</param>
		/// <returns>结果数据对象</returns>
		protected OperateResult<byte[]> ReceiveSolo(Socket socket, bool awaitData)
		{
			if (!Authorization.nzugaydgwadawdibbas())
			{
				return new OperateResult<byte[]>(StringResources.Language.AuthorizationFailed);
			}
			byte[] buffer = new byte[1024];
			MemoryStream memoryStream = new MemoryStream();
			HslTimeOut hslTimeOut = new HslTimeOut
			{
				DelayTime = base.ReceiveTimeOut,
				WorkSocket = socket
			};
			if (base.ReceiveTimeOut > 0)
			{
				ThreadPool.QueueUserWorkItem(base.ThreadPoolSocketCheckTimeOut, hslTimeOut);
			}
			try
			{
				Thread.Sleep(sleepTime);
				int count = socket.Receive(buffer);
				hslTimeOut.IsSuccessful = true;
				memoryStream.Write(buffer, 0, count);
			}
			catch (Exception ex)
			{
				hslTimeOut.IsSuccessful = true;
				memoryStream.Dispose();
				if (hslTimeOut.IsTimeout)
				{
					return new OperateResult<byte[]>(StringResources.Language.ReceiveDataTimeout + " " + base.ReceiveTimeOut + "ms");
				}
				return new OperateResult<byte[]>(ex.Message);
			}
			byte[] value = memoryStream.ToArray();
			memoryStream.Dispose();
			return OperateResult.CreateSuccessResult(value);
		}

		/// <inheritdoc cref="M:HslCommunication.Core.Net.NetworkDeviceSoloBase.ReceiveSolo(System.Net.Sockets.Socket,System.Boolean)" />
		protected async Task<OperateResult<byte[]>> ReceiveSoloAsync(Socket socket, bool awaitData)
		{
			if (!Authorization.nzugaydgwadawdibbas())
			{
				return new OperateResult<byte[]>(StringResources.Language.AuthorizationFailed);
			}
			byte[] buffer = new byte[1024];
			MemoryStream ms = new MemoryStream();
			HslTimeOut hslTimeOut = new HslTimeOut
			{
				DelayTime = base.ReceiveTimeOut,
				WorkSocket = socket
			};
			if (base.ReceiveTimeOut > 0)
			{
				ThreadPool.QueueUserWorkItem(base.ThreadPoolSocketCheckTimeOut, hslTimeOut);
			}
			try
			{
				Thread.Sleep(sleepTime);
				int receiveCount = await Task.Factory.FromAsync(socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, socket), (Func<IAsyncResult, int>)socket.EndReceive);
				hslTimeOut.IsSuccessful = true;
				ms.Write(buffer, 0, receiveCount);
			}
			catch (Exception ex)
			{
				hslTimeOut.IsSuccessful = true;
				ms.Dispose();
				if (hslTimeOut.IsTimeout)
				{
					return new OperateResult<byte[]>(StringResources.Language.ReceiveDataTimeout + " " + base.ReceiveTimeOut + "ms");
				}
				return new OperateResult<byte[]>(ex.Message);
			}
			byte[] result = ms.ToArray();
			ms.Dispose();
			return OperateResult.CreateSuccessResult(result);
		}

		/// <inheritdoc />
		public override OperateResult<byte[]> ReadFromCoreServer(Socket socket, byte[] send)
		{
			base.LogNet?.WriteDebug(ToString(), StringResources.Language.Send + " : " + SoftBasic.ByteToHexString(send, ' '));
			OperateResult operateResult = Send(socket, send);
			if (!operateResult.IsSuccess)
			{
				socket?.Close();
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			if (receiveTimeOut < 0)
			{
				return OperateResult.CreateSuccessResult(new byte[0]);
			}
			OperateResult<byte[]> operateResult2 = ReceiveSolo(socket, awaitData: false);
			if (!operateResult2.IsSuccess)
			{
				socket?.Close();
				return new OperateResult<byte[]>(operateResult2.Message);
			}
			base.LogNet?.WriteDebug(ToString(), StringResources.Language.Receive + " : " + SoftBasic.ByteToHexString(operateResult2.Content, ' '));
			return OperateResult.CreateSuccessResult(operateResult2.Content);
		}

		/// <inheritdoc />
		public override async Task<OperateResult<byte[]>> ReadFromCoreServerAsync(Socket socket, byte[] send)
		{
			base.LogNet?.WriteDebug(ToString(), StringResources.Language.Send + " : " + SoftBasic.ByteToHexString(send, ' '));
			OperateResult sendResult = await SendAsync(socket, send);
			if (!sendResult.IsSuccess)
			{
				socket?.Close();
				return OperateResult.CreateFailedResult<byte[]>(sendResult);
			}
			if (receiveTimeOut < 0)
			{
				return OperateResult.CreateSuccessResult(new byte[0]);
			}
			OperateResult<byte[]> resultReceive = await ReceiveSoloAsync(socket, awaitData: false);
			if (!resultReceive.IsSuccess)
			{
				socket?.Close();
				return new OperateResult<byte[]>(resultReceive.Message);
			}
			base.LogNet?.WriteDebug(ToString(), StringResources.Language.Receive + " : " + SoftBasic.ByteToHexString(resultReceive.Content, ' '));
			return OperateResult.CreateSuccessResult(resultReceive.Content);
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"NetworkDeviceSoloBase<{base.ByteTransform.GetType()}>[{IpAddress}:{Port}]";
		}
	}
}
